The typical workflow of a data transfer application involves reading data from the sender, sending data across a network, and eventually writing data onto the receiver-side storage device. Along this data path, multiple throughput bottlenecks could emerge. Ideally, a transfer session should be able to adjust its rate in response to all possible bottlenecks. Failure to adapt may render the session overdriving the bottlenecked devices, inducing high latency and packet losses.
It is well-known that network links along a transfer path, due to their limited capacity, could become bottlenecked. In the literature, there exists a large body of work focusing on designing adaptation mechanisms to efficiently utilize available link capacities (See, e.g., Lawrence S. Brakmo and Larry L. Peterson. TCP Vegas: end-to-end congestion avoidance on a global Internet. IEEE Journal on Selected Areas in Communications, 13(8):1465-80, October 1995; M. Allman, V. Paxson, and W. Stevens. TCP congestion control. RFC 2581, April 1999; and Frank P. Kelly, Aman Maulloo, and David Tan. Rate control for communication networks: Shadow prices, proportional fairness and stability. Journal of Operations Research Society, 49(3):237-252, March 1998). However, as high-speed networking gear is increasingly deployed, the bottleneck may not happen inside the network, but at the end-systems. In practice, it is common to observe that the storage device on the receiver-end cannot keep up with the data transfer speed. This calls for application level mechanisms that take consideration of the speed of the storage I/O when writing data onto it.